﻿using System;
using System.Linq;
using System.Web.Security;
using System.Transactions;
using VietPublisher.BaseProject;
using VietPublisher.BaseProject.Utils.Miscellaneous;
using VietPublisher.Membership;
using System.Web;
//using SMPS.FX.Data;

namespace VietPublisher.API.Membership
{
    // FormsAuthentication 형식이 봉인되어 있고 정적 멤버를 포함하므로 해당 멤버를 호출하는
    // 코드를 단위 테스트하기 어렵습니다. 아래의 인터페이스 및 도우미 클래스는
    // AccountController 코드를 단위 테스트할 수 있도록 하기 위해 이러한 형식에 추상 래퍼를 만드는
    // 방법을 보여 줍니다.

    public interface IMembershipService
    {
        int MinPasswordLength { get; }

        UserValidateStatus ValidateUser(string userName, string password);

        MembershipCreateStatus CreateUser(string userName, string password, string email);
        MembershipCreateStatus CreateUser(string userName, string password, string email, string storeCode, VietPublisher.BaseProject.Enums.UserTypes userType);
        MembershipCreateStatus CreateUser(string userName, string password, string email, VietPublisher.BaseProject.Enums.UserTypes userType);
        MembershipUser GetUser(string userName);

        /// <summary>
        /// Register user with inactive state
        /// </summary>
        /// <param name="mobilephone"></param>
        /// <param name="fullname"></param>
        /// <param name="email"></param>
        /// <returns></returns>
        MembershipCreateStatus RegisterUser(string userName, string password, string mobilephone, string fullname, string email);

        /// <summary>
        /// 모바일 사용자용
        /// </summary>
        /// <param name="mobilephone"></param>
        void ActivateUser(string mobilephone);
        void DeactivateUser(string mobilephone);

        bool ChangePassword(string userName, string oldPassword, string newPassword);
        bool ChangePassword(string userName, string newPassword);
        string GetPassword(string userName, string email);

        /// <summary>
        /// Delete user from system
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        bool DeleteUser(string userName);
    }

    public class MembershipAPI : IMembershipService
    {
        public int MaxInvalidPasswordAttempts = 5;

        private readonly MembershipProvider _provider;

        public MembershipAPI()
            //: this(null)
        {
            if (_provider == null)
            {
                _provider =  System.Web.Security.Membership.Provider;
            }
        }

        public MembershipAPI(MembershipProvider provider)
        {
            _provider = provider ?? System.Web.Security.Membership.Provider;
        }

        //public MembershipEntities _membershipEnti;

        //public MembershipEntities membershipEntity
        //{
        //    get
        //    {
        //        if (_membershipEnti == null)
        //        {
        //            _membershipEnti = new MembershipEntities();
        //        }
        //        return _membershipEnti;
        //    }
        //}


        public int MinPasswordLength
        {
            get
            {
                return _provider.MinRequiredPasswordLength;
            }
        }

        public UserValidateStatus ValidateUser(string userName, string password)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
            if (String.IsNullOrEmpty(password)) throw new ArgumentException("Value cannot be null or empty.", "password");

            // change user first
            var userInfo = _provider.GetUser(userName, false);
            if (userInfo == null)
            {
                return UserValidateStatus.InvalidUserName;
            }

            bool validated = _provider.ValidateUser(userName, password);
            
            if (!validated)
            {
                if (userInfo.IsLockedOut)
                {
                    return UserValidateStatus.IsLockedOut;
                }

               return UserValidateStatus.InvalidPassword;
            }

            if (userInfo.IsLockedOut)
            {
                _provider.UnlockUser(userName);
            }

            return UserValidateStatus.Success;
        }

        public MembershipCreateStatus CreateUser(string userName, string password, string email,string userTypes)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("값은 null이거나 비어 있을 수 없습니다.", "userName");
            if (String.IsNullOrEmpty(password)) throw new ArgumentException("값은 null이거나 비어 있을 수 없습니다.", "password");
            if (String.IsNullOrEmpty(email)) throw new ArgumentException("값은 null이거나 비어 있을 수 없습니다.", "email");

            MembershipCreateStatus status = MembershipCreateStatus.InvalidProviderUserKey;

            using (TransactionScope scope = new TransactionScope())
            {
                // create user using Membership API (ASP.NET)                    
                _provider.CreateUser(userName, password, email, email, email, true, null, out status);

                if (status != MembershipCreateStatus.Success)
                {
                    throw new Exception(status.ToString());
                }

                // create user extend record
                using (MembershipEntities context = new MembershipEntities())
                {
                    var user = context.aspnet_Users.FirstOrDefault(p => p.LoweredUserName == userName);
                    var userExtend = new T_BK_UserExtend()
                    {
                        UserID = user.UserId,
                        UserName = userName,
                        Name = user.UserName,
                        MobilePhone = string.Empty,
                        UserTypes = (int)VietPublisher.BaseProject.Enums.UserTypes.CUSTOMER,                
                        UseYN = true
                    };

                    context.T_BK_UserExtend.AddObject(userExtend);
                    
                    context.SaveChanges();

                    // Commit
                    scope.Complete();
                }
            }

            return status;
        }

        public MembershipCreateStatus CreateUser(string userName, string password, string email, VietPublisher.BaseProject.Enums.UserTypes userType)
        {
            

            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Username is null.", "userName");
            if (String.IsNullOrEmpty(password)) throw new ArgumentException("password is null.", "password");
            

            MembershipCreateStatus status = MembershipCreateStatus.InvalidProviderUserKey;
            using (TransactionScope scope = new TransactionScope())
            {
                // create user using Membership API (ASP.NET)                    
                _provider.CreateUser(userName, password, email, email, email, true, null, out status);

                if (status != MembershipCreateStatus.Success)
                {
                    throw new Exception(status.ToString());
                }
                scope.Complete();
            }
            return status;
        }

        public bool ChangePassword(string userName, string oldPassword, string newPassword)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("값은 null이거나 비어 있을 수 없습니다.", "userName");
            if (String.IsNullOrEmpty(oldPassword)) throw new ArgumentException("값은 null이거나 비어 있을 수 없습니다.", "oldPassword");
            if (String.IsNullOrEmpty(newPassword)) throw new ArgumentException("값은 null이거나 비어 있을 수 없습니다.", "newPassword");

            // 기본 ChangePassword()는 특정 실패 시나리오에서 false를 반환하지 않고
            // 예외를 throw합니다.
            try
            {
                MembershipUser currentUser = _provider.GetUser(userName, true /* userIsOnline */);
                return currentUser.ChangePassword(oldPassword, newPassword);
            }
            catch (ArgumentException)
            {
                return false;
            }
            catch (MembershipPasswordException)
            {
                return false;
            }
        }

        public bool ChangePassword(string userName, string newPassword)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("값은 null이거나 비어 있을 수 없습니다.", "userName");
            if (String.IsNullOrEmpty(newPassword)) throw new ArgumentException("값은 null이거나 비어 있을 수 없습니다.", "newPassword");

            // 기본 ChangePassword()는 특정 실패 시나리오에서 false를 반환하지 않고
            // 예외를 throw합니다.
            try
            {
                MembershipUser currentUser = _provider.GetUser(userName, true /* userIsOnline */);
                string autoPassword = currentUser.ResetPassword(currentUser.Email);
                return ChangePassword(userName, autoPassword, newPassword);
            }
            catch (ArgumentException)
            {
                return false;
            }
            catch (MembershipPasswordException)
            {
                return false;
            }
        }

        /// <summary>
        /// Get User Password
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public string GetPassword(string userName, string email)
        {
            try
            {
                return _provider.GetPassword(userName, email);
            }
            catch (Exception ex)
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// 사용자 등록
        /// </summary>
        /// <param name="mobilephone"></param>
        /// <param name="fullname"></param>
        /// <param name="email"></param>
        /// <returns></returns>
        public MembershipCreateStatus RegisterUser(string userName, string password, string mobilephone, string fullname, string email)
        {
            if (String.IsNullOrEmpty(email)) throw new ArgumentException("값은 null이거나 비어 있을 수 없습니다.", "email");

            MembershipCreateStatus status;
            _provider.CreateUser(userName, password, email, userName, userName, true, null, out status);
            return status;
        }

        /// <summary>
        /// Get membership user information
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public MembershipUser GetUser(string userName)
        {
            try
            {
                MembershipUser currentUser = _provider.GetUser(userName, true /* userIsOnline */);

                return currentUser;
            }
            catch (Exception ex)
            {
                return null;
            }
        }


        /// <summary>
        /// Approve user
        /// </summary>
        /// <param name="userName"></param>
        public void ActivateUser(string userName)
        {
            try
            {
                MembershipUser currentUser = _provider.GetUser(userName, true /* userIsOnline */);
                currentUser.IsApproved = true;
                _provider.UpdateUser(currentUser);
            }
            catch (ArgumentException)
            {
                return;
            }
            catch (MembershipPasswordException)
            {
                return;
            }
        }

        public void DeactivateUser(string userName)
        {
            try
            {
                MembershipUser currentUser = _provider.GetUser(userName, true /* userIsOnline */);
                currentUser.IsApproved = false;
                _provider.UpdateUser(currentUser);
            }
            catch (ArgumentException)
            {
                return;
            }
            catch (MembershipPasswordException)
            {
                return;
            }
        }


        public bool DeleteUser(string userName)
        {
            try
            {
                return _provider.DeleteUser(userName, true);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }


        public MembershipCreateStatus CreateUser(string userName, string password, string email)
        {
            throw new NotImplementedException();
        }

        public MembershipCreateStatus CreateUser(string userName, string password, string email, string storeCode, Enums.UserTypes userType)
        {
            throw new NotImplementedException();
        }
    }

    public interface IFormsAuthenticationService
    {
        void SignIn(string userName, bool createPersistentCookie);
        void SignOut();
    }

    public class FormsAuthenticationService : IFormsAuthenticationService
    {
        public void SignIn(string userName, bool createPersistentCookie)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");

            FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
            HttpContext.Current.Session[DConst.userName] = userName;
        }

        public void SignOut()
        {
            FormsAuthentication.SignOut();
        }
    }
}

